home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / UGPRG.ZIP / DENTHOR / TUT13.DOC < prev    next >
Encoding:
Text File  |  1996-07-27  |  23.9 KB  |  737 lines

  1.                    ╒═══════════════════════════════╕
  2.                    │         W E L C O M E         │
  3.                    │  To the VGA Trainer Program   │ │
  4.                    │              By               │ │
  5.                    │      DENTHOR of ASPHYXIA      │ │ │
  6.                    ╘═══════════════════════════════╛ │ │
  7.                      ────────────────────────────────┘ │
  8.                        ────────────────────────────────┘
  9.  
  10.                            --==[ PART 13 ]==--
  11.  
  12.  
  13.  
  14. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  15. ■ Introduction
  16.  
  17. Hello again! Here I am, cooped up at home, recovering from my illness
  18. with nothing to do, so of course it is the perfect time to write another
  19. trainer! After the long delay between parts 11 and 12, two trainers in
  20. two days doesn't sound like a bad idea.
  21.  
  22. This trainer is on starfields, which is by request of more then one
  23. person. This is quite an easy effect, and you should have no trouble
  24. grasping the concept behind it. I will be doing a 3d starfield, a
  25. horizontal starfield is very easy with you merely incrementing a x-value
  26. for each star for each frame. I am not even going to bother doing code
  27. for that one (unless requested).
  28.  
  29. So I am off to go grab my antibiotics pills and I will be right back
  30. with the tutorial! ;-)
  31.  
  32.  
  33. If you would like to contact me, or the team, there are many ways you
  34. can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
  35.                   on the ASPHYXIA BBS.
  36.             2) Write to Denthor, EzE, Goth, Fubar or Nobody on Connectix.
  37.             3) Write to :  Grant Smith
  38.                            P.O.Box 270 Kloof
  39.                            3640
  40.                            Natal
  41.                            South Africa
  42.             4) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
  43.                   call during varsity). Call +27-31-73-2129 if you call
  44.                   from outside South Africa. (It's YOUR phone bill ;-))
  45.             5) Write to smith9@batis.bis.und.ac.za in E-Mail.
  46.             6) Write to asphyxia@beastie.cs.und.ac.za
  47.  
  48. NB : If you are a representative of a company or BBS, and want ASPHYXIA
  49.        to do you a demo, leave mail to me; we can discuss it.
  50. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
  51.         quite lonely and want to meet/help out/exchange code with other demo
  52.         groups. What do you have to lose? Leave a message here and we can work
  53.         out how to transfer it. We really want to hear from you!
  54.  
  55.  
  56.  
  57. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  58. ■  What is a 3d starfield?
  59.  
  60. I am not even sure if I should do this bit. Go watch any episode of Star
  61. Trek, the movies, Star Wars, or just about any sci-fi movie. Somewhere
  62. there will be a scene where you can see stars whizzing past the
  63. viewscreen, with the ones that are further away moving slower then the
  64. ones that are passed quite close to.
  65.  
  66. This is a 3d starfield. If you look closely, you will see that all the
  67. stars seem to originate from a point, the point you are travelling
  68. towards.  This is an illusion which thankfully happens automatically,
  69. you don't have to code for it ;)
  70.  
  71. Starfields look very nice, and can make a big difference to an otherwise
  72. black background. It also makes a great screen saver ;-)
  73.  
  74.  
  75. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  76. ■  How do they work?
  77.  
  78. This is actually quite simple. Imagine if you will, each star in the
  79. heavens having an x,y and z coordinate, with you being at 0,0,0. Easy?
  80. Right. Now, if you were to say move forward, ie. increase your z value,
  81. to you you will still be at 0,0,0 , but all the stars z values would
  82. have appeared to decrease by the exact same amount.
  83.  
  84. In easier language, we decrease the z value of all the the stars so that
  85. they come closer to you, and eventually whizz past.
  86.  
  87. This solves all our problems. Stars that are close to us on the x and y
  88. scales will pass us by faster then those that are very far from us on
  89. the x and y scales. The only thing we must watch out for is that no star
  90. is at 0,0 , ie. exactly in front of us, otherwise there will be a
  91. collision which will not look good.
  92.  
  93.  
  94. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  95. ■  How do we code this?
  96.  
  97. The first thing to be done is to generate our starfield. This is quite
  98. easy, with us choosing x values between -160 and 160, and y values
  99. between -100 and 100 randomly. Each z is sequentially greater for each
  100. star so that we don't get large areas with no stars. We must remember to
  101. check that there are no stars at 0,0!
  102.  
  103. Okay, now we start the actual viewing section. Here are the steps :
  104.  
  105. 1) Convert our 3-d coords into their 2-d versions. Have a look at tut 8
  106.    to see how this is done, but basically we divide by z.
  107.  
  108. 2) Clear away all old stars that may be on the screen.
  109.  
  110. 3) Draw all our stars according to our 2-d values we have calculated in
  111.    1)
  112.  
  113. 4) Move all the stars either closer to us or further away from us by
  114.    decreasing or increasing their z values respectively.
  115.  
  116. 5) If a star's z value has passed into the negative, place it at the
  117.    very back of our "queue" so that it will come around again
  118.  
  119. 6) Jump back to 1) ad-infinitum.
  120.  
  121. That is, as they say, it. In our sample program the steps have been
  122. neatly placed into individual procedures for easy reading.
  123.  
  124.  
  125. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  126. ■  What next?
  127.  
  128. Okay, so now we have a cool looking starfield. What next? How about
  129. adding left and right motion? A menu or a scrolly in the foreground? How
  130. about figuring out how a star tunnel works? A cool 3d routine going in
  131. front of the stars?
  132.  
  133. A starfield can make just about any routine look just that much more
  134. professional, and can itself be improved to be a great effect all on
  135. it's own.
  136.  
  137.  
  138. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  139. ■  In closing
  140.  
  141. So, this was yet another effect in the series. Do you still want more
  142. effects, or what? Leave me mail with further ideas for trainers. I may
  143. not do it if you don't ask for it!
  144.  
  145. Oh, well, the medicine has been taken, it is time for me to go. Hello to
  146. all those people who have sent me mail, and those great guys on #coders
  147. in IRC (you know who you are). Wow. That is the first greets I have ever
  148. done in a trainer. Hmm. Maybe I'm just ill ;-)
  149.  
  150. Happy coding people!
  151.   - Denthor
  152.       19:28
  153.         24-7-94
  154.  
  155. The following are official ASPHYXIA distribution sites :
  156.  
  157. ╔══════════════════════════╦════════════════╦═════╗
  158. ║BBS Name                  ║Telephone No.   ║Open ║
  159. ╠══════════════════════════╬════════════════╬═════╣
  160. ║ASPHYXIA BBS #1           ║+27-31-765-5312 ║ALL  ║
  161. ║ASPHYXIA BBS #2           ║+27-31-765-6293 ║ALL  ║
  162. ║C-Spam BBS                ║410-531-5886    ║ALL  ║
  163. ║Connectix BBS             ║+27-31-266-9992 ║ALL  ║
  164. ║POP!                      ║+27-12-661-1257 ║ALL  ║
  165. ║Soul Asylum               ║+358-0-5055041  ║ALL  ║
  166. ║Wasted Image              ║407-838-4525    ║ALL  ║
  167. ╚══════════════════════════╩════════════════╩═════╝
  168.  
  169. Leave me mail if you want to become an official Asphyxia BBS
  170. distribution site.
  171.  
  172.  
  173. Unit GFX2;
  174.  
  175.  
  176. INTERFACE
  177.  
  178. USES crt;
  179. CONST VGA = $A000;
  180.  
  181. TYPE Virtual = Array [1..64000] of byte;  { The size of our Virtual Screen }
  182.      VirtPtr = ^Virtual;                  { Pointer to the virtual screen }
  183.  
  184. VAR Virscr : VirtPtr;                     { Our first Virtual screen }
  185.     Vaddr  : word;                        { The segment of our virtual screen}
  186.  
  187. Procedure SetMCGA;
  188.    { This procedure gets you into 320x200x256 mode. }
  189. Procedure SetText;
  190.    { This procedure returns you to text mode.  }
  191. Procedure Cls (Where:word;Col : Byte);
  192.    { This clears the screen to the specified color }
  193. Procedure SetUpVirtual;
  194.    { This sets up the memory needed for the virtual screen }
  195. Procedure ShutDown;
  196.    { This frees the memory used by the virtual screen }
  197. procedure flip(source,dest:Word);
  198.    { This copies the entire screen at "source" to destination }
  199. Procedure Pal(Col,R,G,B : Byte);
  200.    { This sets the Red, Green and Blue values of a certain color }
  201. Procedure GetPal(Col : Byte; Var R,G,B : Byte);
  202.   { This gets the Red, Green and Blue values of a certain color }
  203. procedure WaitRetrace;
  204.    {  This waits for a vertical retrace to reduce snow on the screen }
  205. Procedure Hline (x1,x2,y:word;col:byte;where:word);
  206.    { This draws a horizontal line from x1 to x2 on line y in color col }
  207. Procedure Line(a,b,c,d:integer;col:byte;where:word);
  208.   { This draws a solid line from a,b to c,d in colour col }
  209. Procedure DrawPoly(x1,y1,x2,y2,x3,y3,x4,y4:integer;color:byte;where:word);
  210.    { This draw a polygon with 4 points at x1,y1 , x2,y2 , x3,y3 , x4,y4
  211.      in color col }
  212. Function rad (theta : real) : real;
  213.    {  This calculates the degrees of an angle }
  214. Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
  215.    { This puts a pixel on the screen by writing directly to memory. }
  216. Function Getpixel (X,Y : Integer; where:word) :Byte;
  217.    { This gets the pixel on the screen by reading directly to memory. }
  218. Procedure LoadCEL (FileName :  string; ScrPtr : pointer);
  219.   { This loads the cel 'filename' into the pointer scrptr }
  220.  
  221.  
  222. IMPLEMENTATION
  223.  
  224. {──────────────────────────────────────────────────────────────────────────}
  225. Procedure SetMCGA;  { This procedure gets you into 320x200x256 mode. }
  226. BEGIN
  227.   asm
  228.      mov        ax,0013h
  229.      int        10h
  230.   end;
  231. END;
  232.  
  233. {──────────────────────────────────────────────────────────────────────────}
  234. Procedure SetText;  { This procedure returns you to text mode.  }
  235. BEGIN
  236.   asm
  237.      mov        ax,0003h
  238.      int        10h
  239.   end;
  240. END;
  241.  
  242. {──────────────────────────────────────────────────────────────────────────}
  243. Procedure Cls (Where:word;Col : Byte); assembler;
  244.    { This clears the screen to the specified color }
  245. asm
  246.    push    es
  247.    mov     cx, 32000;
  248.    mov     es,[where]
  249.    xor     di,di
  250.    mov     al,[col]
  251.    mov     ah,al
  252.    rep     stosw
  253.    pop     es
  254. End;
  255.  
  256. {──────────────────────────────────────────────────────────────────────────}
  257. Procedure SetUpVirtual;
  258.    { This sets up the memory needed for the virtual screen }
  259. BEGIN
  260.   GetMem (VirScr,64000);
  261.   vaddr := seg (virscr^);
  262. END;
  263.  
  264. {──────────────────────────────────────────────────────────────────────────}
  265. Procedure ShutDown;
  266.    { This frees the memory used by the virtual screen }
  267. BEGIN
  268.   FreeMem (VirScr,64000);
  269. END;
  270.  
  271. {──────────────────────────────────────────────────────────────────────────}
  272. procedure flip(source,dest:Word); assembler;
  273.   { This copies the entire screen at "source" to destination }
  274. asm
  275.   push    ds
  276.   mov     ax, [Dest]
  277.   mov     es, ax
  278.   mov     ax, [Source]
  279.   mov     ds, ax
  280.   xor     si, si
  281.   xor     di, di
  282.   mov     cx, 32000
  283.   rep     movsw
  284.   pop     ds
  285. end;
  286.  
  287. {──────────────────────────────────────────────────────────────────────────}
  288. Procedure Pal(Col,R,G,B : Byte); assembler;
  289.   { This sets the Red, Green and Blue values of a certain color }
  290. asm
  291.    mov    dx,3c8h
  292.    mov    al,[col]
  293.    out    dx,al
  294.    inc    dx
  295.    mov    al,[r]
  296.    out    dx,al
  297.    mov    al,[g]
  298.    out    dx,al
  299.    mov    al,[b]
  300.    out    dx,al
  301. end;
  302.  
  303. {──────────────────────────────────────────────────────────────────────────}
  304. Procedure GetPal(Col : Byte; Var R,G,B : Byte);
  305.   { This gets the Red, Green and Blue values of a certain color }
  306. Var
  307.    rr,gg,bb : Byte;
  308. Begin
  309.    asm
  310.       mov    dx,3c7h
  311.       mov    al,col
  312.       out    dx,al
  313.  
  314.       add    dx,2
  315.  
  316.       in     al,dx
  317.       mov    [rr],al
  318.       in     al,dx
  319.       mov    [gg],al
  320.       in     al,dx
  321.       mov    [bb],al
  322.    end;
  323.    r := rr;
  324.    g := gg;
  325.    b := bb;
  326. end;
  327.  
  328. {──────────────────────────────────────────────────────────────────────────}
  329. procedure WaitRetrace; assembler;
  330.   {  This waits for a vertical retrace to reduce snow on the screen }
  331. label
  332.   l1, l2;
  333. asm
  334.     mov dx,3DAh
  335. l1:
  336.     in al,dx
  337.     and al,08h
  338.     jnz l1
  339. l2:
  340.     in al,dx
  341.     and al,08h
  342.     jz  l2
  343. end;
  344.  
  345. {──────────────────────────────────────────────────────────────────────────}
  346. Procedure Hline (x1,x2,y:word;col:byte;where:word); assembler;
  347.   { This draws a horizontal line from x1 to x2 on line y in color col }
  348. asm
  349.   mov   ax,where
  350.   mov   es,ax
  351.   mov   ax,y
  352.   mov   di,ax
  353.   shl   ax,8
  354.   shl   di,6
  355.   add   di,ax
  356.   add   di,x1
  357.  
  358.   mov   al,col
  359.   mov   ah,al
  360.   mov   cx,x2
  361.   sub   cx,x1
  362.   shr   cx,1
  363.   jnc   @start
  364.   stosb
  365. @Start :
  366.   rep   stosw
  367. end;
  368.  
  369. {──────────────────────────────────────────────────────────────────────────}
  370. Procedure Line(a,b,c,d:integer;col:byte;where:word);
  371.   { This draws a solid line from a,b to c,d in colour col }
  372.   function sgn(a:real):integer;
  373.   begin
  374.        if a>0 then sgn:=+1;
  375.        if a<0 then sgn:=-1;
  376.        if a=0 then sgn:=0;
  377.   end;
  378. var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer;
  379. begin
  380.      u:= c - a;
  381.      v:= d - b;
  382.      d1x:= SGN(u);
  383.      d1y:= SGN(v);
  384.      d2x:= SGN(u);
  385.      d2y:= 0;
  386.      m:= ABS(u);
  387.      n := ABS(v);
  388.      IF NOT (M>N) then
  389.      BEGIN
  390.           d2x := 0 ;
  391.           d2y := SGN(v);
  392.           m := ABS(v);
  393.           n := ABS(u);
  394.      END;
  395.      s := m shr 1;
  396.      FOR i := 0 TO m DO
  397.      BEGIN
  398.           putpixel(a,b,col,where);
  399.           s := s + n;
  400.           IF not (s<m) THEN
  401.           BEGIN
  402.                s := s - m;
  403.                a:= a + d1x;
  404.                b := b + d1y;
  405.           END
  406.           ELSE
  407.           BEGIN
  408.                a := a + d2x;
  409.                b := b + d2y;
  410.           END;
  411.      end;
  412. END;
  413.  
  414.  
  415. {──────────────────────────────────────────────────────────────────────────}
  416. Procedure DrawPoly(x1,y1,x2,y2,x3,y3,x4,y4:integer;color:byte;where:word);
  417.   { This draw a polygon with 4 points at x1,y1 , x2,y2 , x3,y3 , x4,y4
  418.     in color col }
  419. var
  420.   x:integer;
  421.   mny,mxy:integer;
  422.   mnx,mxx,yc:integer;
  423.   mul1,div1,
  424.   mul2,div2,
  425.   mul3,div3,
  426.   mul4,div4:integer;
  427.  
  428. begin
  429.   mny:=y1; mxy:=y1;
  430.   if y2<mny then mny:=y2;
  431.   if y2>mxy then mxy:=y2;
  432.   if y3<mny then mny:=y3;
  433.   if y3>mxy then mxy:=y3;    { Choose the min y mny and max y mxy }
  434.   if y4<mny then mny:=y4;
  435.   if y4>mxy then mxy:=y4;
  436.  
  437.   if mny<0 then mny:=0;
  438.   if mxy>199 then mxy:=199;
  439.   if mny>199 then exit;
  440.   if mxy<0 then exit;        { Verticle range checking }
  441.  
  442.   mul1:=x1-x4; div1:=y1-y4;
  443.   mul2:=x2-x1; div2:=y2-y1;
  444.   mul3:=x3-x2; div3:=y3-y2;
  445.   mul4:=x4-x3; div4:=y4-y3;  { Constansts needed for intersection calc }
  446.  
  447.   for yc:=mny to mxy do
  448.     begin
  449.       mnx:=320;
  450.       mxx:=-1;
  451.       if (y4>=yc) or (y1>=yc) then
  452.         if (y4<=yc) or (y1<=yc) then   { Check that yc is between y1 and y4 }
  453.           if not(y4=y1) then
  454.             begin
  455.               x:=(yc-y4)*mul1 div div1+x4; { Point of intersection on x axis }
  456.               if x<mnx then
  457.                 mnx:=x;
  458.               if x>mxx then
  459.                 mxx:=x;       { Set point as start or end of horiz line }
  460.             end;
  461.       if (y1>=yc) or (y2>=yc) then
  462.         if (y1<=yc) or (y2<=yc) then   { Check that yc is between y1 and y2 }
  463.           if not(y1=y2) then
  464.             begin
  465.               x:=(yc-y1)*mul2 div div2+x1; { Point of intersection on x axis }
  466.               if x<mnx then
  467.                 mnx:=x;
  468.               if x>mxx then
  469.                 mxx:=x;       { Set point as start or end of horiz line }
  470.             end;
  471.       if (y2>=yc) or (y3>=yc) then
  472.         if (y2<=yc) or (y3<=yc) then   { Check that yc is between y2 and y3 }
  473.           if not(y2=y3) then
  474.             begin
  475.               x:=(yc-y2)*mul3 div div3+x2; { Point of intersection on x axis }
  476.               if x<mnx then
  477.                 mnx:=x;
  478.               if x>mxx then
  479.                 mxx:=x;       { Set point as start or end of horiz line }
  480.             end;
  481.       if (y3>=yc) or (y4>=yc) then
  482.         if (y3<=yc) or (y4<=yc) then   { Check that yc is between y3 and y4 }
  483.           if not(y3=y4) then
  484.             begin
  485.               x:=(yc-y3)*mul4 div div4+x3; { Point of intersection on x axis }
  486.               if x<mnx then
  487.                 mnx:=x;
  488.               if x>mxx then
  489.                 mxx:=x;       { Set point as start or end of horiz line }
  490.             end;
  491.       if mnx<0 then
  492.         mnx:=0;
  493.       if mxx>319 then
  494.         mxx:=319;          { Range checking on horizontal line }
  495.       if mnx<=mxx then
  496.         hline (mnx,mxx,yc,color,where);   { Draw the horizontal line }
  497.     end;
  498.   end;
  499.  
  500. {──────────────────────────────────────────────────────────────────────────}
  501. Function rad (theta : real) : real;
  502.   {  This calculates the degrees of an angle }
  503. BEGIN
  504.   rad := theta * pi / 180
  505. END;
  506.  
  507. {──────────────────────────────────────────────────────────────────────────}
  508. Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); assembler;
  509.   { This puts a pixel on the screen by writing directly to memory. }
  510. Asm
  511.   mov     ax,[where]
  512.   mov     es,ax
  513.   mov     bx,[X]
  514.   mov     dx,[Y]
  515.   mov     di,bx
  516.   mov     bx, dx                  {; bx = dx}
  517.   shl     dx, 8
  518.   shl     bx, 6
  519.   add     dx, bx                  {; dx = dx + bx (ie y*320)}
  520.   add     di, dx                  {; finalise location}
  521.   mov     al, [Col]
  522.   stosb
  523. End;
  524.  
  525. {──────────────────────────────────────────────────────────────────────────}
  526. Function Getpixel (X,Y : Integer; where:word):byte; assembler;
  527.   { This puts a pixel on the screen by writing directly to memory. }
  528. Asm
  529.   mov     ax,[where]
  530.   mov     es,ax
  531.   mov     bx,[X]
  532.   mov     dx,[Y]
  533.   mov     di,bx
  534.   mov     bx, dx                  {; bx = dx}
  535.   shl     dx, 8
  536.   shl     bx, 6
  537.   add     dx, bx                  {; dx = dx + bx (ie y*320)}
  538.   add     di, dx                  {; finalise location}
  539.   mov     al, es:[di]
  540. End;
  541.  
  542. {──────────────────────────────────────────────────────────────────────────}
  543. Procedure LoadCEL (FileName :  string; ScrPtr : pointer);
  544.   { This loads the cel 'filename' into the pointer scrptr }
  545. var
  546.   Fil : file;
  547.   Buf : array [1..1024] of byte;
  548.   BlocksRead, Count : word;
  549. begin
  550.   assign (Fil, FileName);
  551.   reset (Fil, 1);
  552.   BlockRead (Fil, Buf, 800);    { Read and ignore the 800 byte header }
  553.   Count := 0; BlocksRead := $FFFF;
  554.   while (not eof (Fil)) and (BlocksRead <> 0) do begin
  555.     BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead);
  556.     Count := Count + 1024;
  557.   end;
  558.   close (Fil);
  559. end;
  560.  
  561.  
  562.  
  563.  
  564. BEGIN
  565. END.{$X+}
  566. USES GFX2,crt;
  567.  
  568. CONST Num = 400;     { Number of stars }
  569.  
  570. TYPE Star = Record
  571.               x,y,z:integer;
  572.             End;     { Information on each star }
  573.      Pos = Record
  574.              x,y:integer;
  575.            End;      { Information on each point to be plotted }
  576.  
  577. VAR Stars : Array [1..num] of star;
  578.     Clear : Array [1..2,1..num] of pos;
  579.  
  580. {──────────────────────────────────────────────────────────────────────────}
  581. Procedure Init;
  582. VAR loop1,loop2:integer;
  583.     logo:array [1..50,1..320] of byte;
  584. BEGIN
  585.   for loop1:=1 to num do
  586.     Repeat
  587.       stars[loop1].x:=random (320)-160;
  588.       stars[loop1].y:=random (200)-100;
  589.       stars[loop1].z:=loop1;
  590.     Until (stars[loop1].x<>0) and (stars[loop1].y<>0);
  591.       { Make sure no stars are heading directly towards the viewer }
  592.   pal (32,00,00,30);
  593.   pal (33,10,10,40);
  594.   pal (34,20,20,50);
  595.   pal (35,30,30,60);   { Pallette for the stars coming towards you }
  596.  
  597.   pal (247,20,20,20);
  598.   pal (136,30,0 ,0 );
  599.   pal (101,40,0 ,0 );
  600.   pal (19 ,60,0 ,0 );  { Pallette for the logo at the top of the screen }
  601.  
  602.   loadcel ('logo.cel',addr(logo));
  603.   for loop1:=0 to 319 do
  604.     for loop2:=1 to 50 do
  605.       putpixel (loop1,loop2-1,logo[loop2,loop1+1],vga);
  606.     { Placing the logo at the top of the screen }
  607. END;
  608.  
  609. {──────────────────────────────────────────────────────────────────────────}
  610. Procedure Calcstars;
  611.   { This ccalculates the 2-d coordinates of our stars and saves these values
  612.     into the variable clear }
  613. VAR loop1,x,y:integer;
  614. BEGIN
  615.   For loop1:=1 to num do BEGIN
  616.     x:=((stars[loop1].x shl 7) div stars[loop1].z)+160;
  617.     y:=((stars[loop1].y shl 7) div stars[loop1].z)+100;
  618.     clear[1,loop1].x:=x;
  619.     clear[1,loop1].y:=y;
  620.   END;
  621. END;
  622.  
  623. {──────────────────────────────────────────────────────────────────────────}
  624. Procedure Drawstars;
  625.   { This draws the 2-d values stored in clear to the vga screen, with various
  626.     colors according to how far away it is. }
  627. VAR loop1,x,y:integer;
  628. BEGIN
  629.   For loop1:=1 to num do BEGIN
  630.     x:=clear[1,loop1].x;
  631.     y:=clear[1,loop1].y;
  632.     if (x>0) and (x<320) and (y>50) and (y<200) then
  633.       If stars[loop1].z>400 then putpixel(x,y,32,vga)
  634.       else
  635.       If stars[loop1].z>300 then putpixel(x,y,33,vga)
  636.       else
  637.       If stars[loop1].z>200 then putpixel(x,y,34,vga)
  638.       else
  639.       If stars[loop1].z>100 then putpixel(x,y,34,vga)
  640.       else
  641.       putpixel(x,y,35,vga)
  642.   END;
  643. END;
  644.  
  645. {──────────────────────────────────────────────────────────────────────────}
  646. Procedure Clearstars;
  647.   { This clears the 2-d values from the vga screen, which is faster then a
  648.     cls (vga,0) }
  649. VAR loop1,x,y:integer;
  650. BEGIN
  651.   For loop1:=1 to num do BEGIN
  652.     x:=clear[2,loop1].x;
  653.     y:=clear[2,loop1].y;
  654.     if (x>0) and (x<320) and (y>50) and (y<200) then
  655.       putpixel (x,y,0,vga);
  656.   END;
  657. END;
  658.  
  659.  
  660. {──────────────────────────────────────────────────────────────────────────}
  661. Procedure MoveStars (Towards:boolean);
  662.   { If towards is True, then the z-value of each star is decreased to come
  663.     towards the viewer, otherwise the z-value is increased to go away from
  664.     the viewer }
  665. VAR loop1:integer;
  666. BEGIN
  667.   If towards then
  668.     for loop1:=1 to num do BEGIN
  669.       stars[loop1].z:=stars[loop1].z-2;
  670.       if stars[loop1].z<1 then stars[loop1].z:=stars[loop1].z+num;
  671.     END
  672.     else
  673.     for loop1:=1 to num do BEGIN
  674.       stars[loop1].z:=stars[loop1].z+2;
  675.       if stars[loop1].z>num then stars[loop1].z:=stars[loop1].z-num;
  676.     END;
  677. END;
  678.  
  679. {──────────────────────────────────────────────────────────────────────────}
  680. Procedure Play;
  681.   { This is our main procedure }
  682. VAR ch:char;
  683. BEGIN
  684.   Calcstars;
  685.   Drawstars;  { This draws our stars for the first time }
  686.   ch:=#0;
  687.   Repeat
  688.     if keypressed then ch:=readkey;
  689.     clear[2]:=clear[1];
  690.     Calcstars;     { Calculate new star positions }
  691.     waitretrace;
  692.     Clearstars;    { Erase old stars }
  693.     Drawstars;     { Draw new stars }
  694.     if ch=' ' then Movestars(False) else Movestars(True);
  695.       { Move stars towards or away from the viewer }
  696.   Until ch=#27;
  697.     { Until the escape key is pressed }
  698. END;
  699.  
  700. BEGIN
  701.   clrscr;
  702.   writeln ('Hello! Another effect for you, this one is on starfields, again by');
  703.   writeln ('request.  In this sample program, a starfield will be coming towards');
  704.   writeln ('you. Hit the space bar to have it move away from you, any other key');
  705.   writeln ('to have it come towards you again. Hit [ESC] to end.');
  706.   writeln;
  707.   Writeln ('The logo at the top of the screen was drawn by me in Autodesk Animator.');
  708.   Writeln ('It only took a few seconds, so please don''t laugh too much at my attempt.');
  709.   writeln;
  710.   writeln ('The code is very easy to follow, and the documentation is as usual in the');
  711.   writeln ('main text. Leave me mail with further ideas for future trainers.');
  712.   writeln;
  713.   writeln;
  714.   write ('Hit any key to continue ...');
  715.   readkey;
  716.   randomize;
  717.   setmcga;
  718.   init;
  719.   Play;
  720.   settext;
  721.   Writeln ('All done. This concludes the thirteenth sample program in the ASPHYXIA');
  722.   Writeln ('Training series. You may reach DENTHOR under the names of GRANT');
  723.   Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS. I am also an avid');
  724.   Writeln ('Connectix BBS user, and occasionally read RSAProg. E-mail me at :');
  725.   Writeln ('    smith9@batis.bis.und.ac.za');
  726.   Writeln ('The numbers are available in the main text. You may also write to me at:');
  727.   Writeln ('             Grant Smith');
  728.   Writeln ('             P.O. Box 270');
  729.   Writeln ('             Kloof');
  730.   Writeln ('             3640');
  731.   Writeln ('             Natal');
  732.   Writeln ('             South Africa');
  733.   Writeln ('I hope to hear from you soon!');
  734.   Writeln; Writeln;
  735.   Write   ('Hit any key to exit ...');
  736.   readkey;
  737. END.